package com.uu.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.uu.global.StandardResult;
import lombok.SneakyThrows;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@RestControllerAdvice
public class RestResultAdvice implements ResponseBodyAdvice<Object> {

  private static ObjectMapper objectMapper = new ObjectMapper();

  /**
   * 判断是否要对返回值做处理，这里我们都返回true
   *
   * @param returnType
   * @param converterType
   * @return
   */
  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    return true;
  }

  /**
   * messageConvert在调用write方法前会调用该方法进行message自定义转换
   *
   * @param body                  controller 返回的值
   * @param returnType            具体执行的方法和返回值的封装
   * @param selectedContentType
   * @param selectedConverterType
   * @param request               ServerHttpRequest对象
   * @param response              ServerHttpResponse对象
   * @return
   */
  @SneakyThrows
  @Override
  public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

    if (body instanceof StandardResult) {
      return body;
    }

    Object wrap = StandardResult.builder().code("success").data(body).build();
    if (this.isNative(body)) {
      return objectMapper.writeValueAsString(wrap);
    }
    return wrap;
  }

  /**
   * 对String类型的返回值要做特殊处理，不能进行类型的转换，只能还是返回String类型； 因为在 org.springframework.http.converter.StringHttpMessageConverter#getContentLength(java.lang.String, org.springframework.http.MediaType) 方法会报错
   *
   * @param body
   * @return
   */
  private boolean isNative(Object body) {
    return body instanceof String;
  }
}
